package com.heima.article.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.*;
import com.heima.article.service.ApArticleService;
import com.heima.common.constants.article.ArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.common.exception.CustomException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.feigns.behavior.BehaviorFegin;
import com.heima.feigns.user.UserFeign;
import com.heima.model.Utils.threadlocal.AppThreadLocalUtils;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.article.dto.ArticleHomeDto;
import com.heima.model.article.dto.ArticleInfoDto;
import com.heima.model.article.pojo.*;
import com.heima.model.article.vo.HotArticleVo;
import com.heima.model.behavior.dto.ApArticleRelationDto;
import com.heima.model.behavior.pojo.ApBehaviorEntry;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojo.ApUser;
import com.heima.model.user.pojo.ApUserFollow;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    AuthorMapper authorMapper;
    @Autowired
    ApArticleConfigMapper apArticleConfigMapper;
    @Autowired
    ApArticleContentMapper apArticleContentMapper;
    @Value("${file.oss.web-site}")
    String webSite;

    /**
     * 保存三张表的信息
     *
     * @param articleDto
     * @return
     */
    @Override
    public ResponseResult saveArticle(ArticleDto articleDto) {
        //1.将dto转为转为article对象
        ApArticle apArticle = BeanUtil.toBeanIgnoreError(articleDto, ApArticle.class);
        //根据作者名称查询作者id
        ApAuthor apAuthor = authorMapper.selectOne(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getName, articleDto.getAuthorName()));
        if (apAuthor == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST, "作者信息不存在");
        }
        apArticle.setAuthorId(apAuthor.getId().longValue());
        //判断文章id是否存在
        if (apArticle.getId() == null) {
            //如果id为空 保存文章

            apArticle.setLikes(0);
            apArticle.setComment(0);
            apArticle.setViews(0);
            apArticle.setCollection(0);
            save(apArticle);
        } else {
            //如果id不为空 修改文章
            updateById(apArticle);
            // 将之前关联的文章配置 和文章的内容删除
            apArticleConfigMapper.delete(Wrappers.<ApArticleConfig>lambdaQuery().eq(ApArticleConfig::getArticleId, apArticle.getId()));
            apArticleContentMapper.delete(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, apArticle.getId()));

        }
        //统一保存配置信息, 保存文章内容信息
        ApArticleConfig articleConfig = new ApArticleConfig();
        articleConfig.setArticleId(apArticle.getId());
        articleConfig.setIsComment(true); //可以评论
        articleConfig.setIsForward(true); //可以转发
        articleConfig.setIsDown(false);   //上架
        articleConfig.setIsDelete(false); //未删除
        //插入文章对应配置信息
        apArticleConfigMapper.insert(articleConfig);
        ApArticleContent content = new ApArticleContent();
        content.setArticleId(apArticle.getId());
        content.setContent(articleDto.getContent());
        //插入对应文章内容表
        apArticleContentMapper.insert(content);
        //返回文章id
        return ResponseResult.okResult(apArticle.getId());
    }

    @Autowired
    private ApArticleMapper apArticleMapper;

    /**
     * 加载列表  (上划加载最新,下滑加载更多)
     *
     * @param loadtypeLoadNew
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(Short type, ArticleHomeDto dto) {
        //检查参数
        Integer size = dto.getSize();
        if (size == null || size < 1) {
            dto.setSize(10);
        }
        if (dto.getMaxBehotTime() == null) {
            dto.setMaxBehotTime(new Date());
        }
        if (dto.getMinBehotTime() == null) {
            dto.setMinBehotTime(new Date());
        }
        if (dto.getTag() == null) {
            dto.setTag(ArticleConstants.DEFAULT_TAG);
        }
        //调用mapper
        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto, type);

        ResponseResult responseResult = ResponseResult.okResult(apArticles);
        responseResult.setHost(webSite);
        return responseResult;
    }

    /**
     * app文章详情-功能实现
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult loadArticleInfo(ArticleInfoDto dto) {
        // 1 参数检查
        if (dto == null || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        Long articleId = dto.getArticleId();
        //查询文章信息配置config
        ApArticleConfig articleConfig = apArticleConfigMapper.selectOne(Wrappers.<ApArticleConfig>lambdaQuery()
                .eq(ApArticleConfig::getArticleId, articleId));
        //数据库中tinint 1为false 0为true
        if (articleConfig == null || articleConfig.getIsDelete() || articleConfig.getIsDown()) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章已下架");
        }
        //查询文章内容
        ApArticleContent content = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery()
                .eq(ApArticleContent::getArticleId, articleId));
        if (content == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
        }
        //4. 返回封装结果
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("config", articleConfig);
        resultMap.put("content", content);

        return ResponseResult.okResult(resultMap);

    }

    @Autowired
    private ArticleFeign articleFeign;
    @Autowired
    private UserFeign userFeign;
    @Autowired
    private BehaviorFegin behaviorFegin;
    @Autowired
    private ApCollectionMapper apCollectionMapper;

    /**
     * 加载文章详情的行为内容
     * 需远程调用user服务查询是否关注作者 行为微服务的文章点赞和不喜欢
     * 和本服务下的是否收藏  是否收藏写在本服务是因为和后期个人中心有查询已收藏的文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult loadArticleBehavior(ArticleInfoDto dto) {
        boolean isfollow = false, iscollection = false;
        //检查参数
        if (dto.getArticleId() == null || dto.getAuthorId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据作者id 得到作者的信息
        ApAuthor apAuthor = articleFeign.findByUserId(dto.getAuthorId());
        ApUser user = AppThreadLocalUtils.getUser();

        if (apAuthor != null && user != null) {
            //查询登录用户id 远程查询关注信息
            ApUserFollow userFollow = userFeign.findByUserIdAndFollowId(user.getId(), apAuthor.getUserId());
            if (userFollow != null) {
                isfollow = true;
            }
        }
        //远程查询点赞和不喜欢的信息
        ApArticleRelationDto apArticleRelationDto = new ApArticleRelationDto();
        apArticleRelationDto.setArticleId(dto.getArticleId());
        if (user == null) {
            apArticleRelationDto.setEntryId(dto.getEquipmentId());
            apArticleRelationDto.setType(ApBehaviorEntry.Type.EQUIPMENT.getCode());
        } else {
            apArticleRelationDto.setEntryId(user.getId());
            apArticleRelationDto.setType(ApBehaviorEntry.Type.USER.getCode());
        }

        Map result = behaviorFegin.findApArticleRelation(apArticleRelationDto);
        Object entryId = result.get("entryId");
        if (entryId != null) {
            //根据文章id 和行为实体id 在当前微服务中 查询是否收藏的信息
            ApCollection apCollection = apCollectionMapper.selectOne(Wrappers.<ApCollection>lambdaQuery()
                    .eq(ApCollection::getArticleId, dto.getArticleId())
                    .eq(ApCollection::getEntryId, entryId)
            );
            if (apCollection != null) {
                iscollection = true;
            }

        }
        //将所有信息分装成一个map集合返回
        result.put("iscollection", iscollection);
        result.put("isfollow", isfollow);

        return ResponseResult.okResult(result);
    }

    /**
     * 重新计算文章分值
     *
     * @param mess
     */
    @Override
    public void updateApArticle(ArticleVisitStreamMess mess) {
        log.info("updateApArticle is begin: {}", mess);
        //根据传递来的id 查询文章数据
        ApArticle apArticle = getById(mess.getArticleId());
        if (apArticle == null) {
            log.error("apArticle is null id:{}", mess.getArticleId());
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 更新文章指定的行为数据
        if (mess.getView() != 0) {
            apArticle.setViews(apArticle.getViews() == null ? (int) mess.getView() : (int) mess.getView() + apArticle.getViews());

        }
        if (mess.getCollect() != 0) {
            apArticle.setCollection(apArticle.getCollection() == null ? (int) mess.getCollect() : (int) mess.getView() + apArticle.getCollection());

        }
        if (mess.getComment() != 0) {
            apArticle.setComment(apArticle.getComment() == null ? (int) mess.getComment() : (int) mess.getComment() + apArticle.getComment());

        }
        if (mess.getLike() != 0) {
            apArticle.setLikes(apArticle.getLikes() == null ? (int) mess.getLike() : (int) mess.getLike() + apArticle.getLikes());

        }
        updateById(apArticle);
        // 按照权重计算文章分值 今日整体权重*3
        Integer score = computeScore(apArticle);
        score = score * 3;
        //判断当前文章 在所属频道中 能否排行到热点文章前30 替换分值较低热点文章
        updateArticleCache(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());
        //判断当前文章 在所有频道中 能否排行到热点文章的前30 替换分值较低热点文章
        updateArticleCache(apArticle, score, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);

    }

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 更新热点文章缓存
     *
     * @param apArticle 待更新的文章
     * @param score     该文章的热度分值
     * @param cacheKey  缓存的key
     */
    private void updateArticleCache(ApArticle apArticle, Integer score, String cacheKey) {
        String hotArticleListJson = redisTemplate.opsForValue().get(cacheKey);
        if (StringUtils.isBlank(hotArticleListJson)) {
            log.error("缓存热点文章失败");
            return;
        }

        List<HotArticleVo> hotArticleVoList = JSON.parseArray(hotArticleListJson, HotArticleVo.class);
        //stream 流不能修改源集合 只能修改后得到新的
        boolean ishas = false;
        for (HotArticleVo hotArticleVo : hotArticleVoList) {
            if (hotArticleVo.getId().equals(apArticle.getId())) {
                ishas = true;
            }
                break;
        }
        //如果不存在 将当前文章封装成vo添加到 热点文章集合中
        if (!ishas) {
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle, hotArticleVo);
            hotArticleVo.setScore(score);
            hotArticleVoList.add(hotArticleVo);
        }
        //将最终的热点文章集合 按照得分降序排序 取前30 条文章
        hotArticleVoList = hotArticleVoList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .limit(30).collect(Collectors.toList());

        //将新的30 条文章重新缓存到redis中
        redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(hotArticleVoList));

    }

    //计算文章分值方法
    private Integer computeScore(ApArticle apArticle) {
        int score = 0;
        //评论
        if (apArticle.getComment() != null) {
            score += apArticle.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        //收藏
        if (apArticle.getCollection() != null) {
            score += apArticle.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        //点赞
        if (apArticle.getLikes() != null) {
            score += apArticle.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        //阅读
        if (apArticle.getViews() != null) {
            score += apArticle.getViews() * ArticleConstants.HOT_ARTICLE_VIEW_WEIGHT;
        }

        return score;
    }
    /**
     * 根据参数加载文章列表  v2
     *
     * @param loadtypeLoadMore
     * @param dto
     * @param firstPage
     * @return
     */
    @Override
    public ResponseResult load2(Short loadtypeLoadMore, ArticleHomeDto dto, boolean firstPage) {
        if(firstPage){
            String jsonStr = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
            if(StringUtils.isNotBlank(jsonStr)){
                List<HotArticleVo> hotArticleVoList = JSON.parseArray(jsonStr, HotArticleVo.class);
                if(!hotArticleVoList.isEmpty()&& hotArticleVoList.size() > 0){
                    ResponseResult responseResult = ResponseResult.okResult(hotArticleVoList);
                    responseResult.setHost(webSite);
                    log.info("从缓存中加载");
                    return responseResult;

                }

            }

        }
        return load(loadtypeLoadMore,dto);
    }
}